
package xj.lang;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

public class CodeWriter {

  public static CodeWriter getCodeWriter(String filename) { 
    if (filename != null) { 
      File file = new File(filename); 
      try {
	/* 
	   if (!file.exists()) { 
	   file.createNewFile(); 
	   }
	*/
	return new CodeWriter(new PrintWriter(new BufferedWriter(new FileWriter(file))));
      } catch (IOException e) {
	e.printStackTrace();
      } 
    }
    return null; 
  }

  /*- requires: out != null -*/ 
  public CodeWriter(PrintWriter out) {
    this.out = out; 
  }

  public PrintWriter getPrintWriter() { 
    return out; 
  }

  public int getLineNumber() { 
    return lineNumber;
  }

  public int getLineLength() { 
    return lineLength;
  }

  public void print(String s) {
    if (s != null) {
      line.add(s);
      lineLength += stringLength(s); 
    }
  }

  public void println(String s) {
    if (s != null) {
      print(s);
      linebreak();
    } 
  }

  public void println() {
    linebreak(); 
  }

  public void noIndent() {
    curIndent = 0; 
  }

  public void linebreak() {
    flushLine(); 
    curIndent = indentLevel;
    lineLength = indentLevel * indentSize; 
    lineNumber++;
  }

  public void space() {
    space(0); 
  }

  public void space(int i) {
    line.add(new Space(i)); 
    lineLength++; 
  }

  public void close() {
    out.flush(); 
    out.close(); 
  }

  public void indentInc() { 
    if (indentLevel < maxIndentLevel) {
      indentLevel++; 
    }
  }

  public void indentDec() { 
    if (indentLevel > 0) {
      indentLevel--; 
    }
  }

  public void thisIndentInc() { 
    if (curIndent < maxIndentLevel) {
      curIndent++;
      indentLevel++; 
      lineLength += indentSize; 
    }
  }

  public void thisIndentDec() { 
    if (curIndent > 0) {
      curIndent--;
      indentLevel--; 
      lineLength -= indentSize; 
    }
  }
  
  public int getIndentSize() { 
    return indentSize; 
  }
 
  public int getMaxIndentLevel() { 
    return maxIndentLevel;
  }

  public int getTabSize() { 
    return tabSize;
  } 

  public void setIndentSize(int sz) { 
    if (sz < 0) {
      sz = 0; 
    }
    if (sz > 8) {
      sz = 8; 
    }
    indentSize = sz; 
  }
 
  public void setMaxIndentLevel(int mi) { 
    if (mi < 1) {
      mi = 1; 
    }
    int ma = lineLength / indentSize;
    maxIndentLevel =  (mi > ma) ? ma : mi; 
  }

  public void setTabSize(int sz) { 
    if (sz < 0) {
      sz = 0; 
    }
    if (sz > 8) {
      sz = 8; 
    }
    tabSize = sz; 
  } 

  public int getIndentLevel() { 
    return indentLevel;
  }

  protected void flushLine() {
    if (curIndent > 0) { 
      out.print(makeSpace(curIndent * indentSize)); 
    }
    for (int i = 0; i < line.size(); i++) {
      out.print(line.get(i)); 
    }
    out.println(); 
    line.clear(); 
    lineLength = 0; 
  }

  protected int stringLength(String s) {
    int len = 0; 
    int sl = s.length(); 
    for (int i = 0; i < sl; i++) {
      switch (s.charAt(i)) {
      case '\t':
	while ((++len % tabSize) != 0);       
	break; 
      default:
	len++;
	break; 
      }
    }
    return len; 
  }

  protected String makeSpace(int count) {
    if (count > 0) {
      char ca[] = new char[count]; 
      for (int i = 0; i < count; i++) {
	ca[i] = ' '; 
      }
      return new String(ca); 
    } else {
      return ""; 
    }
  }

  protected PrintWriter out; 
  protected int maxLineLength = 80;
  protected int indentLevel = 0, indentSize = 2, maxIndentLevel = 20;
  protected int tabSize = 8;

  // the current line
  protected List<Object> line = new ArrayList<Object>(); 
  protected int curIndent = 0; 
  protected int lineLength = 0;
  protected int lineNumber = 0;
  
}

class Space {
  public Space(int g) {
    glue = g; 
  }

  @Override
public String toString() {
    return " "; 
  }

  public int glue; 

}
